/*
* Copyright (C) Microsoft. All rights reserved.  
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not 
* use this file except in compliance with the License.  You may obtain a copy 
* of the License at http://www.apache.org/licenses/LICENSE-2.0  
* 
* THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED 
* WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, 
* MERCHANTABLITY OR NON-INFRINGEMENT. 
*
* See the Apache License, Version 2.0 for specific language governing 
* permissions and limitations under the License.
*
*/
#pragma once

#include <baja/common.hpp>
#include <baja/service.hpp>
#include <baja/math.hpp>
#include <baja/eventable.hpp>
#include <baja/vars.hpp>
#include <ppltasks.h>
#include <baja/stream/storage_file_interface.h>

#include <baja/graphics/graphics_fwd.hpp>
#include <baja/graphics/graphics_types.hpp>

namespace baja { namespace graphics {

namespace m = baja::math;

// renderObject is an BAJA_INTERFACE_BEGIN(others implement to participate in the 
// rendering pipeline of the render service.
struct irender_object : public ibase
{
    BAJA_INTERFACE(irender_object, "F7A20A9B-8415-482F-90F7-643EB04E8E17")

    virtual int32 getPriority() = 0;

    virtual void render(
        const std::shared_ptr<iengine>& graphics
        ) = 0;

    virtual void onAddedToRenderService(
        const std::shared_ptr<irender_service>& renderService
        ) = 0;

    virtual void onRemovedFromRenderService(
        const std::shared_ptr<irender_service>& renderService
        ) = 0;
};

// renderService is the service that provides a rendering pipeline via render 
// objects along with graphics initialization and teardown logic which observers 
// can participate in.
struct irender_service : public ibase
{
    BAJA_INTERFACE(irender_service, "09D881B7-5C38-4552-A446-EE7C12021406")
    
    // rendering

    virtual void addRenderObject(
        const std::shared_ptr<irender_object>& renderObject
        ) = 0;

    virtual void removeRenderObject(
        const std::shared_ptr<irender_object>& renderObject
        ) = 0;

    virtual void render(
        const std::shared_ptr<iengine>& graphics
        ) = 0;

    virtual float32 getFramesPerSecond() = 0;
        
    // resizing

    virtual int32 addResizeHandler(const event_source<resize_event_args>::handler_type& handler, void* context = nullptr) = 0;

    virtual void removeResizeHandler(const int32 cookie) = 0;

    virtual void resize(
        const std::shared_ptr<iengine>& graphics
        ) = 0;

    // graphics initialization

    virtual int addInitializeHandler(const event_source<event_args>::handler_type& handler, void* context = nullptr) = 0;
    virtual void removeInitializeHandler(const int32 cookie) = 0;
    virtual int addTeardownHandler(const event_source<event_args>::handler_type& handler, void* context = nullptr) = 0;
    virtual void removeTeardownHandler(const int32 cookie) = 0;

    virtual void initialize(const std::shared_ptr<iengine>& graphics) = 0;
    virtual void teardown(const std::shared_ptr<iengine>& graphics) = 0;
};

// font represents a simple fixed-width aSCII character based 
// font which can be used for quick efficient render of aSCII text strings
struct ifont : public ibase
{
    BAJA_INTERFACE(ifont, "69EC9DDE-2815-4244-A15F-3521CC16453A")
    
    virtual void measureText(
        const wchar* text,
        const horizontal_alignment horzAlignment,
        const vertical_alignment vertAlignment,
        const bool includeOverhang,
        m::rectangle* rect
        ) = 0;

    virtual void renderText(
        const std::shared_ptr<iengine>& graphics,
        const wchar* text,
        const packed_color color,
        const horizontal_alignment horzAlignment,
        const vertical_alignment vertAlignment,
        const m::rectangle* rect
        ) = 0;
};

// assetManager manages texture and mesh assets which are loaded from disk.
// only 1 copy per asset is loaded at any given time, in order to minimize memory usage.
struct iasset_manager : public ibase
{
    BAJA_INTERFACE(iasset_manager, "9AFF028B-499E-4c16-96C0-E57FCE4CCBCD")

    virtual std::shared_ptr<ifont> getOrCreateFont(
        const std::shared_ptr<iengine>& graphics,
        const wchar* fontName,
        const uint32 fontHeight,
        const bool rightToLeft
        ) = 0;

    virtual std::shared_ptr<ieffect2> addEffect(
        const std::shared_ptr<iengine>& graphics, 
        const std::shared_ptr<effect2_description>& desc
        ) = 0;

    virtual std::shared_ptr<ieffect2> getOrCreateEffect(
        const std::shared_ptr<iengine>& graphics,
        const std::shared_ptr<effect2_description>& desc
        ) = 0;

    virtual std::shared_ptr<ieffect2> getEffect(
        const wchar* effectName
        ) = 0;

    virtual std::shared_ptr<itexture> getOrCreateTextureFromFile(
        const std::shared_ptr<iengine>& graphics,
        const wchar* filename,
        const pixel_format format
        ) = 0;

    virtual void addTexture(
        const wchar* filename, 
        const std::shared_ptr<itexture>& texture
        ) = 0;

    virtual std::shared_ptr<itexture> getTexture(const wchar* filename) = 0;

    virtual void addMesh(
        const wchar* meshName,
        const std::shared_ptr<imesh>& mesh
        ) = 0;

    virtual std::shared_ptr<imesh> getMesh(
        const wchar* meshName
        ) = 0;

    virtual void addVertexDeclaration(
        const wchar* vertexDeclarationName,
        const std::shared_ptr<ivertex_declaration>& vertexDeclaration
        ) = 0;

    virtual std::shared_ptr<ivertex_declaration> getVertexDeclaration(
        const wchar* vertexDeclarationName,
        bool noThrow = false
        ) = 0;
};

// material represents a material used when rendering. this describes
// the properties of a material such as color and textures associated with
// the material.
struct imaterial : public ibase
{
    BAJA_INTERFACE(imaterial, "89273BB7-0F17-489f-9B94-A3E9320BB4CD")

    virtual color getAmbientColor() = 0;
    virtual void setAmbientColor(const color& color) = 0;
    virtual void setAmbientColorPacked(const packed_color color) = 0;

    virtual color getDiffuseColor() = 0;
    virtual void setDiffuseColor(const color& color) = 0;
    virtual void setDiffuseColorPacked(const packed_color color) = 0;

    virtual color getEmissiveColor() = 0;
    virtual void setEmissiveColor(const color& color) = 0;
    virtual void setEmissiveColorPacked(const packed_color color) = 0;

    virtual color getSpecularColor() = 0;
    virtual void setSpecularColor(const color& color) = 0;
    virtual void setSpecularColorPacked(const packed_color color) = 0;

    virtual float32 getSpecularPower() = 0;
    virtual void setSpecularPower(const float32 specularPower) = 0;

    virtual std::shared_ptr<itexture> getTexture() = 0;
    virtual std::shared_ptr<itexture> getTextureAtIndex(const uint32 index) = 0;

    virtual void setTexture(const std::shared_ptr<itexture>& texture) = 0;
    virtual void setTextureAtIndex(const uint32 index, const std::shared_ptr<itexture>& texture) = 0;

    virtual std::shared_ptr<imaterial> clone() = 0;

    virtual bool equals(const std::shared_ptr<imaterial>& material) = 0;

    virtual bool getIsDirty() = 0;
    virtual void resetIsDirty() = 0;
};

// materialCollection represents a collection of material used when rendering. 
struct imaterial_collection : public ibase
{
    BAJA_INTERFACE(imaterial_collection, "44AF0E9C-1A8D-4947-A623-3DE2A298D40D")

    virtual size_t getMaterialCount() = 0;

    virtual std::shared_ptr<imaterial> getMaterial(const size_t index) = 0;
    virtual std::shared_ptr<imaterial> getMaterialByName(const char* name) = 0;

    virtual std::shared_ptr<imaterial_collection> clone() = 0;
};

// collisionResolver tests and resolves different types of collisions.
struct icollision_resolver : public ibase
{
    BAJA_INTERFACE(icollision_resolver, "7D941D33-AE69-41B1-A63C-848F2B05CCB3")

    virtual bool lineToMeshHitTest(
        const m::line3d& line, 
        const std::shared_ptr<imesh>& mesh, 
        float32* intersectingT
        ) = 0;
};

// mesh represents a mesh and associated animations for the mesh.
struct imesh : public ibase
{
    BAJA_INTERFACE(imesh, "9090722D-501D-4321-A248-63405070EC94")

    virtual void render(
        const std::shared_ptr<iengine>& graphics,
        const std::shared_ptr<imaterial_collection>& materials, 
        const m::matrix44* localToWorld, 
        const standard_effect standardEffect
        ) = 0;

    virtual void renderWithEffect(
        const std::shared_ptr<iengine>& graphics, 
        const std::shared_ptr<imaterial_collection>& materials, 
        const m::matrix44* localToWorld,
        const std::shared_ptr<ieffect2>& effect
        ) = 0;

    virtual std::shared_ptr<imaterial_collection> cloneMaterialCollection() = 0;

    virtual bool lineHitTest(
        const m::line3d& line, 
        float32* intersectingT
        ) = 0;

    virtual std::shared_ptr<icollision_resolver> getCollisionResolver() = 0;
    virtual void setCollisionResolver(const std::shared_ptr<icollision_resolver>& collisionResolver) = 0;

    virtual std::shared_ptr<ivertex_buffer> vertexBuffer() = 0;
    virtual std::shared_ptr<iindex_buffer> indexBuffer() = 0;	
};

// sceneTransformer represents an interface that manages scene transformations
// given a *snapshot* of the current world/camera/projection matrices. changes to
// the graphics transforms will nOT affect the scene transformer.
struct iscene_transformer : public ibase
{
    BAJA_INTERFACE(iscene_transformer, "CE95E6FA-471B-44c6-8A5F-246E9DB6E84E")

    virtual void setTransforms(
        const render_transforms& transforms, 
        const viewport& viewport, 
        const float32 minDepth, 
        const float32 maxDepth
        ) = 0;

    virtual m::line3d pixelToCameraSpace(
        const m::point2d& pixel
        ) = 0;

    virtual m::line3d pixelToWorldSpace(
        const m::point2d& pixel
        ) = 0;

    virtual m::point2d cameraSpaceToPixel(
        const m::point3d& point,
        float32* zDepth) = 0;

    virtual m::point2d worldSpaceToPixel(
        const m::point3d& point,
        float32* zDepth) = 0;
};

// dynamicVertexBuffer class manages a dynamic vertex buffer,
// allowing consumer to add new vertices and also handles rendering 
// of the buffer for the consumer.
struct idynamic_vertex_buffer : public ibase
{
    BAJA_INTERFACE(idynamic_vertex_buffer, "93164A7C-BFB0-4027-B57E-D4365740A9EB")

    virtual void begin(
        const std::shared_ptr<iengine>& graphics,
        const primitive_type primitive
        ) = 0;

    virtual void addVertices(
        const std::shared_ptr<iengine>& graphics,
        const void* vertexData,
        const uint32 vertexSize,
        const uint32 vertexCount
        ) = 0;

    virtual void end(
        const std::shared_ptr<iengine>& graphics
        ) = 0;

    virtual void reset() = 0;
};

struct texture_description
{
    const wchar* name;
    const uint32 slot;

    texture_description(
        const wchar* name_,
        const uint32 slot_) : name(name_), slot(slot_) {}
};

struct constant_buffer_description
{
    const wchar* name;
    const uint32 byteSize;
    const uint32 slot;

    constant_buffer_description() : name(nullptr), byteSize(0), slot(0) {}
    constant_buffer_description(const constant_buffer_description& other) : name(other.name), byteSize(other.byteSize), slot(other.slot) {}

    constant_buffer_description(
        const wchar *name_,
        const uint32 byteSize_,
        const uint32 slot_) : name(name_), byteSize(byteSize_), slot(slot_) {}
};

struct state_description
{
    const wchar* name;
    std::vector<const memory> bytes;

    state_description() : name(nullptr) {}

    state_description(
        const wchar* name_, 
        const void* data,
        const size_t size) : name(name_) 
    {
        bytes.resize(size);
        std::memcpy(bytes.data(), data, size);
    }

    state_description(
        const wchar* name_,
        const std::vector<const memory>& bytes_) : name(name_), bytes(bytes_) {}
};

struct effect2_description
{
    const wchar* name;
    const wchar* pixelShaderFile;
    const wchar*  vertexShaderFile;
    std::vector<constant_buffer_description> constantBufferDesc;
    std::vector<texture_description> textureDesc;
    std::vector<state_description> blendStateDesc;
    std::vector<state_description> samplerStateDesc;

    effect2_description() : name(nullptr), pixelShaderFile(nullptr), vertexShaderFile(nullptr) {}
    effect2_description(const effect2_description& other) : 
        name(other.name), 
        pixelShaderFile(other.pixelShaderFile), 
        vertexShaderFile(other.vertexShaderFile),
        constantBufferDesc(other.constantBufferDesc),
        textureDesc(other.textureDesc)
    {}

    effect2_description(
        const wchar* name_,
        const wchar* pixelShaderFile_,
        const wchar* vertexShaderFile_
        ) : name(name_), pixelShaderFile(pixelShaderFile_), vertexShaderFile(vertexShaderFile_) {}
};

struct ieffect2 : public ibase
{
    BAJA_INTERFACE(ieffect2, "CCAB7164-245E-443F-88DF-0440F820DC3D")

    virtual void begin(const std::shared_ptr<iengine>& graphics, const uint32 context = 0) = 0;
    virtual void end(const std::shared_ptr<iengine>& graphics, const uint32 context = 0) = 0;
    virtual void setConstantBuffer(const wchar* name, const void* buffer, const uint32 context = 0) = 0;
    virtual void setTexture(const wchar* name, const std::shared_ptr<itexture>& texture, const uint32 context = 0) = 0;
    virtual void setSamplerState(const wchar* name, const uint32 context = 0) = 0;
    virtual void setBlendState(const wchar* name, const float32* blendFactor, uint32 sampleMask, const uint32 context = 0) = 0;
    virtual size_t pixelShaderSize() = 0;
    virtual const void* pixelShaderBytes() = 0;
    virtual size_t vertexShaderSize() = 0;
    virtual const void* vertexShaderBytes() = 0;
};

// indexBuffer represents an index buffer used when drawing graphics primitives
struct iindex_buffer : public ibase
{
    BAJA_INTERFACE(iindex_buffer, "8D1F0FFD-9B37-4e14-A10D-8EBAE966564D")

    virtual void lock(memory** data) = 0;
    virtual void unlock() = 0;
    virtual void lockNoOverwrite(memory** data, const uint32 offset, const uint32 sizeToLock) = 0;

    virtual uint32 getSize() = 0;
};

// surface represents a graphic surface composed of pixels
struct isurface : public ibase
{
    BAJA_INTERFACE(isurface, "74ECB8A5-32B9-4423-91C2-5C36EAECEB37")

    virtual uint32 getWidth() = 0;
    virtual uint32 getHeight() = 0;
    virtual pixel_format getPixelFormat() = 0;

    virtual uint32 getBitsPerPixel() = 0;

    virtual void lock(const lock_type lockType, memory** data, uint32* pitch) = 0;

    virtual void unlock() = 0;

    /*
    NYI:
    virtual void saveToFile(
        const wchar* file,
        file_format format) = 0;

    virtual void saveToStream(
        iStream* toStream, 
        file_format format) = 0;
        */
};

// texture represents a texture used for rendering
struct itexture : public isurface
{
    BAJA_INTERFACE(itexture, "F3C39854-48F4-418a-AB8E-C66A9F57546E")

    virtual uint32 getArraySize() = 0;
    virtual uint32 getMipLevelCount() = 0;
    
    // copy data from the texture to system memory.
    // sourceX, sourceY, sourceWidth, sourceHeight define the region of the 
    // texture to copy.
    // data is allocated and filled in. caller is responsible for freeing 
    // the memory.
    virtual size_t calculateSize(
        const uint32 sourceWidth,
        const uint32 sourceHeight
        ) = 0;
    virtual void copyToSystemMemory(
        const uint32 mipLevel,
        const uint32 sourceX,
        const uint32 sourceY,
        const uint32 sourceWidth,
        const uint32 sourceHeight,
        memory* p
        ) = 0;

    // copy data from system memory back to the texture.
    // destX, destY is the top-left coordinate in the texture where we 
    // start writing data.
    // dataX, dataY, dataWidth, dataHeight define the rectangle in the 
    // data memory that we need to copy.
    virtual void copyFromSystemMemory(
        const uint32 mipLevel,
        const uint32 destX,
        const uint32 destY,
        const uint32 dataX,
        const uint32 dataY,
        const uint32 dataWidth,
        const uint32 dataHeight,
        const memory* data,
        const uint32 dataSizeInBytes,
        const uint32 dataBytesPerPixel,
        const uint32 pitch
        ) = 0;
};

// vertexBuffer represents a vertex buffer used when drawing graphics primitives
struct ivertex_buffer : public ibase
{
    BAJA_INTERFACE(ivertex_buffer, "9550DDC1-DA99-4f67-AA00-2FB6CDB964B3")

    virtual void lockDiscard(memory** data, const uint32 context = 0) = 0;

    virtual void lockNoOverwrite( 
        const uint32 offset,
        const uint32 sizeToLock,
        memory** data,
        const uint32 context = 0
        ) = 0;

    virtual void unlock(const uint32 context = 0) = 0;

    virtual uint32 getSize() = 0;
};

// vertexDeclaration represents a custom vertex data declaration
struct ivertex_declaration : public ibase
{
    BAJA_INTERFACE(ivertex_declaration, "B932AF07-A3F5-43b8-B02C-C6F1265A9A95")

    virtual void beginDefinition(const uint32 totalElements) = 0;

    virtual void addElement(
        const uint32 streamIndex,
        const uint32 byteOffset,
        const vertex_decl_type elementType,
        const vertex_decl_usage elementUsage,
        const uint32 usageIndex) = 0;

    virtual void endDefinition(
        const void* shaderBytes, 
        const size_t shaderSize
        ) = 0;
};

// engine represents the graphics engine, managing render states and 
// scene management.
struct iengine : public ibase
{
    BAJA_INTERFACE(iengine, "02BA35E9-9E6B-457d-9057-27D0C578074C")

    virtual display_params getDisplayParams() = 0;
    virtual void changeDisplayParams(const display_params& displayParams) = 0;

    // resource creation
    virtual bool getMultisampleLevels(const pixel_format format, uint32* msaaCount, uint32* msaaQualityLevel) = 0;

    virtual std::shared_ptr<ieffect2> createEffect(const std::shared_ptr<effect2_description>& desc) = 0;

    virtual std::shared_ptr<itexture> createTexture( 
        const uint32 width,
        const uint32 height,
        const uint32 mipLevels,
        const uint32 usage,
        const pixel_format format,
        const memory_pool pool,
        const uint32 msaaCount = 1,
        const uint32 msaaQuality = 0
        ) = 0;

    virtual concurrency::task<std::shared_ptr<itexture>> createTextureFromFileAsync(
        const wchar* filename,
        const uint32 usage,
        const pixel_format format,
        const memory_pool pool,
        const mipmap_load mipmapLoading
        ) = 0;

    virtual void createTextureFromFileAsync(
        const std::shared_ptr<baja::storage::istorage_file>& file,
        const uint32 usage,
        const pixel_format format,
        const memory_pool pool,
        const mipmap_load mipmapLoading,
        std::function<void(bool success, const std::shared_ptr<graphics::itexture>& texture)> createCompletedFunc
        ) = 0;

    virtual std::shared_ptr<itexture> createTextureFromFile(
        const wchar* filename,
        const uint32 usage,
        const pixel_format format,
        const memory_pool pool,
        const mipmap_load mipmapLoading
        ) = 0;

    virtual std::shared_ptr<itexture> createTextureFromFileInMemory( 
        const memory* data,
        const uint32 dataSize,
        const uint32 usage,
        const pixel_format format,
        const memory_pool pool,
        const mipmap_load mipmapLoading
        ) = 0;

    virtual std::shared_ptr<isurface> createDepthStencilSurface( 
        const uint32 width,
        const uint32 height,
        const pixel_format format,
        const bool useFSAA
        ) = 0;

    virtual std::shared_ptr<isurface> createOffscreenSurface( 
        const uint32 width,
        const uint32 height,
        const pixel_format format
        ) = 0;

    virtual std::shared_ptr<isurface> createRenderTarget( 
        const uint32 width,
        const uint32 height,
        const pixel_format format,
        bool useFSAA
        ) = 0;

    virtual std::shared_ptr<ivertex_buffer> createVertexBuffer( 
        const uint32 totalBytes,
        const vertex_buffer_usage usage,
        const std::shared_ptr<iengine>& graphics
        ) = 0;

    virtual std::shared_ptr<iindex_buffer> createIndexBuffer(const uint32 totalIndices, const index_buffer_usage usage, const std::shared_ptr<iengine>& graphics) = 0;

    virtual std::shared_ptr<ivertex_declaration> createVertexDeclaration() = 0;

    virtual void setVertexDeclaration(const std::shared_ptr<ivertex_declaration>& vertexDecl, const uint32 context = 0) = 0;

    // render state management

    virtual bool getIsHardwareAccelerated() = 0;
    virtual void setAlphaBlend(const enabled_state state, const uint32 context = 0) = 0;
    virtual void setAmbientLight(const color& color) = 0;
    virtual void setBlendOp(const blend_op_state& state, const uint32 context = 0) = 0;
    virtual void setCulling(const cull_state state, const uint32 context = 0) = 0;
    virtual void setDstBlend(const blend_state state, const uint32 context = 0) = 0;
    virtual void setFillMode(const fill_mode state, const uint32 context = 0) = 0;
    virtual void setIndices(const std::shared_ptr<iindex_buffer>& indexBuffer, const uint32 context = 0) = 0;
    virtual void setLight(const uint32 index, const light& light) = 0;
    virtual void setLightEnable(const uint32 index, const enabled_state state) = 0;
    virtual void setMaterial(const std::shared_ptr<imaterial>& material) = 0;
    virtual void setSrcBlend(const blend_state state, const uint32 context = 0) = 0;
    virtual void setStencil(const enabled_state state, const uint32 context = 0) = 0;
    virtual void setStencilFail(const stencil_op state, const uint32 context = 0) = 0;
    virtual void setStencilZFail(const stencil_op state, const uint32 context = 0) = 0;
    virtual void setStencilPass(const stencil_op state, const uint32 context = 0) = 0;
    virtual void setStencilCompare(const compare_state state, const uint32 context = 0) = 0;
    virtual void setStencilRefValue(const uint32 refValue, const uint32 context = 0) = 0;
    virtual void setStencilCompareMaskValue(const uint32 maskValue, const uint32 context = 0) = 0;
    virtual void setStencilWriteMaskValue(const uint32 maskValue, const uint32 context = 0) = 0;

    virtual void setStreamSource(
        const uint32 streamIndex,
        std::shared_ptr<ivertex_buffer>& streamData,
        const uint32 offsetInBytes,
        const uint32 vertexStride,
        const uint32 context = 0
        ) = 0;

    virtual void setTexture(
        const uint32 textureIndex,
        const std::shared_ptr<itexture>& texture) = 0;


    virtual void updateEffectTextures(const std::shared_ptr<ieffect2>& effect, const uint32 context = 0) = 0;
    virtual void setTime(const float32 time) = 0;

    virtual void getViewport(viewport* vp, const uint32 context = 0) = 0;
    virtual void setViewport(const viewport& vp, const uint32 context = 0) = 0;

    virtual void setZBias(const int32 bias, const uint32 context = 0) = 0;
    virtual void setZBuffer(const enabled_state state, const uint32 context = 0) = 0;
    virtual void setZCompare(const compare_state state, const uint32 context = 0) = 0;
    virtual void setZWrite(const enabled_state state, const uint32 context = 0) = 0;

    virtual void generateMips(const std::shared_ptr<itexture>& texture) = 0;

    virtual std::shared_ptr<iasset_manager> getAssetManager() = 0;

    virtual void clear(
        const clear_targets clearTargets,
        const packed_color packedColor,
        const float32 zValue,
        const uint32 stencilValue) = 0;

    virtual std::shared_ptr<iscene_transformer> snapshotCurrentSceneTransforms() = 0;
    
    // render target / surface management

    virtual std::shared_ptr<isurface> getRenderTarget(const uint32 context = 0) = 0;

    virtual std::shared_ptr<isurface> getDepthStencilTarget(const uint32 context = 0) = 0;

    virtual void setRenderTargets(
        const std::shared_ptr<isurface>& renderTarget,
        const std::shared_ptr<isurface>& depthStencilTarget,
        const uint32 context = 0
        ) = 0;

    virtual render_mode getRenderMode() = 0;
    virtual void setRenderMode(const render_mode renderMode) = 0;

    virtual void getBackBufferSize(uint32* width, uint32* height) = 0;

    // drawing 

    virtual void drawPrimitive(
        const primitive_type primitive,
        const uint32 startVertex,
        const uint32 primitiveCount,
        const uint32 context = 0
        ) = 0;

    virtual void drawIndexedPrimitive(
        const primitive_type primitive,
        const int32 baseVertexIndex,
        const uint32 minVertexIndex,
        const uint32 numVertices,
        const uint32 startIndex,
        const uint32 primitiveCount,
        const uint32 context = 0) = 0;

    // scene transformation management
    
    virtual void pushWorldMatrix(const m::matrix44& world, const bool combineWithCurrentWorld) = 0;
    virtual void popWorldMatrix() = 0;

    virtual void pushCameraMatrix(const m::matrix44& camera) = 0;
    virtual void replaceCurrentCameraMatrix(const m::matrix44& camera) = 0;
    virtual void popCameraMatrix() = 0;

    virtual void pushOrthographicProjection(
        const float32 left, 
        const float32 right, 
        const float32 top, 
        const float32 bottom, 
        const float32 nearZ, 
        const float32 farZ) = 0;

    virtual void pushPerspectiveProjection(
        const float32 widthAtFocalPoint,
        const float32 heightAtFocalPoint, 
        const float32 nearZ,
        const float32 focalPointZ,
        const float32 farZ) = 0;

    virtual void replaceCurrentProjectionWithOrthographicProjection(
        const float32 left, 
        const float32 right, 
        const float32 top, 
        const float32 bottom, 
        const float32 nearZ, 
        const float32 farZ) = 0;

    virtual void replaceCurrentProjectionWithPerspectiveProjection(
        const float32 widthAtFocalPoint,
        const float32 heightAtFocalPoint, 
        const float32 nearZ,
        const float32 focalPointZ,
        const float32 farZ) = 0;

    virtual void popProjectionMatrix() = 0;

    virtual void pushUVMatrix(const m::matrix44& uvMatrix) = 0;
    virtual void popUVMatrix() = 0;

    virtual m::matrix44 getCoordinateSystemMatrix() = 0;
    virtual void setCoordinateSystemMatrix(const m::matrix44& worldMatrix) = 0;

    virtual m::matrix44 getWorldMatrix() = 0;
    virtual m::matrix44 getWorldToProjectedMatrix() = 0;
    virtual m::matrix44 getWorldToCameraMatrix() = 0;

    // scene management

    virtual std::shared_ptr<ieffect2> getStandardEffect(const standard_effect standardEffect) = 0;

    virtual void begin(const primitive_type primitive) = 0;
    virtual void beginScreenSpace(const primitive_type primitive) = 0;

    virtual void setColor(const packed_color packedColor) = 0;
    virtual void setNormal(const m::vector3d& normal) = 0;
    virtual void setTextureCoordinate(const texture_coordinate& texCoord) = 0;
    virtual void setVertex(const m::point3d& position) = 0;
    virtual void setScreenSpaceVertex(const m::point4d& position) = 0;

    virtual void end() = 0;
    
    virtual void beginScene() = 0;
    virtual void endScene() = 0;
    virtual void showScene() = 0;
    virtual void executeDeferred() = 0;

    // misc

    virtual std::shared_ptr<ivar_group> getVarGroup() = 0;
};

}} // namespace baja.graphics
